import { Service } from "egg";
import * as bcrypt from "bcryptjs";
import { v4 as uuidv4 } from "uuid";
import { Op } from "sequelize";

/**
 * 用户服务类 (Sequelize版本)
 * 负责用户相关的数据库操作和业务逻辑
 */
export default class UserSequelizeService extends Service {
  /**
   * 用户注册
   * @param username 用户名
   * @param password 明文密码
   * @returns 注册结果
   */
  public async register(username: string, password: string) {
    const { models } = this.app as any;

    try {
      // 1. 检查用户名是否已存在
      const existingUser = await models.User.findOne({
        where: { username }
      });

      if (existingUser) {
        return {
          success: false,
          message: "用户名已存在",
          code: "USERNAME_EXISTS"
        };
      }

      // 2. 生成密码盐值和哈希
      const salt = this.generateSalt();
      const passwordHash = await this.hashPassword(password, salt);

      // 3. 创建新用户
      const newUser = await models.User.create({
        username,
        password_hash: passwordHash,
        salt,
        status: 1, // 1-正常状态
        login_count: 0
      });

      // 4. 返回成功结果（不包含敏感信息）
      return {
        success: true,
        message: "注册成功",
        data: {
          userId: newUser.id,
          username: newUser.username,
          createdAt: newUser.created_at
        }
      };
    } catch (error) {
      this.logger.error("用户注册失败:", error);
      return {
        success: false,
        message: "注册失败，请稍后重试",
        code: "REGISTER_ERROR"
      };
    }
  }

  /**
   * 用户登录验证
   * @param username 用户名
   * @param password 明文密码
   * @param loginInfo 登录信息（IP、User-Agent等）
   * @returns 登录结果
   */
  public async login(username: string, password: string, loginInfo: any) {
    const { models, sequelize } = this.app as any;

    // 使用事务确保数据一致性
    const transaction = await sequelize.transaction();

    try {
      // 1. 查找用户
      const user = await models.User.findOne({
        where: { username },
        transaction
      });

      // 2. 记录登录尝试日志的基础数据
      const logData = {
        username,
        ip_address: loginInfo.ip,
        user_agent: loginInfo.userAgent,
        login_result: 0 // 先设为失败，成功时再更新
      };

      if (!user) {
        // 用户不存在
        await models.LoginLog.create(
          {
            ...logData,
            failure_reason: "用户不存在"
          },
          { transaction }
        );

        await transaction.commit();

        return {
          success: false,
          message: "用户名或密码错误",
          code: "INVALID_CREDENTIALS"
        };
      }

      // 3. 检查用户状态
      if (user.status !== 1) {
        await models.LoginLog.create(
          {
            ...logData,
            user_id: user.id,
            failure_reason: "用户已被禁用"
          },
          { transaction }
        );

        await transaction.commit();

        return {
          success: false,
          message: "账户已被禁用，请联系管理员",
          code: "USER_DISABLED"
        };
      }

      // 4. 验证密码
      const isPasswordValid = await this.verifyPassword(password, user.password_hash, user.salt);

      if (!isPasswordValid) {
        await models.LoginLog.create(
          {
            ...logData,
            user_id: user.id,
            failure_reason: "密码错误"
          },
          { transaction }
        );

        await transaction.commit();

        return {
          success: false,
          message: "用户名或密码错误",
          code: "INVALID_CREDENTIALS"
        };
      }

      // 5. 登录成功，先清理该用户的旧会话
      await models.UserSession.update(
        { is_active: 0 }, // 将旧会话标记为失效
        {
          where: {
            user_id: user.id,
            is_active: 1
          },
          transaction
        }
      );

      // 6. 生成新会话
      const sessionId = uuidv4();
      const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24小时后过期

      // 7. 存储新会话信息
      await models.UserSession.create(
        {
          session_id: sessionId,
          user_id: user.id,
          session_data: JSON.stringify({
            userId: user.id,
            username: user.username,
            loginTime: new Date()
          }),
          ip_address: loginInfo.ip,
          user_agent: loginInfo.userAgent,
          expires_at: expiresAt,
          is_active: 1
        },
        { transaction }
      );

      // 8. 更新用户登录信息
      await user.update(
        {
          last_login_at: new Date(),
          last_login_ip: loginInfo.ip,
          login_count: user.login_count + 1
        },
        { transaction }
      );

      // 9. 记录成功登录日志
      await models.LoginLog.create(
        {
          ...logData,
          user_id: user.id,
          login_result: 1,
          session_id: sessionId,
          failure_reason: null
        },
        { transaction }
      );

      await transaction.commit();

      // 10. 返回登录成功结果
      return {
        success: true,
        message: "登录成功",
        data: {
          sessionId,
          user: {
            id: user.id,
            username: user.username,
            lastLoginAt: new Date(),
            loginCount: user.login_count + 1
          }
        }
      };
    } catch (error) {
      await transaction.rollback();
      this.logger.error("用户登录失败:", error);
      return {
        success: false,
        message: "登录失败，请稍后重试",
        code: "LOGIN_ERROR"
      };
    }
  }

  /**
   * 验证会话有效性
   * @param sessionId 会话ID
   * @returns 验证结果
   */
  public async validateSession(sessionId: string) {
    const { models } = this.app as any;

    try {
      // 1. 查找有效会话，同时获取用户信息
      const session = await models.UserSession.findOne({
        where: {
          session_id: sessionId,
          is_active: 1
        },
        include: [
          {
            model: models.User,
            as: "user",
            where: { status: 1 }
          }
        ]
      });

      if (!session) {
        return {
          success: false,
          message: "会话不存在或已失效",
          code: "SESSION_NOT_FOUND"
        };
      }

      // 2. 检查会话是否过期
      if (new Date() > new Date(session.expires_at)) {
        // 标记会话为失效
        await session.update({
          is_active: 0
        });

        return {
          success: false,
          message: "会话已过期，请重新登录",
          code: "SESSION_EXPIRED"
        };
      }

      const user = (session as any).user;

      // 3. 更新会话最后访问时间
      await session.update({
        updated_at: new Date()
      });

      // 4. 返回验证成功结果
      return {
        success: true,
        message: "会话有效",
        data: {
          sessionId,
          user: {
            id: user.id,
            username: user.username,
            status: user.status,
            lastLoginAt: user.last_login_at
          },
          sessionData: JSON.parse(session.session_data || "{}")
        }
      };
    } catch (error) {
      this.logger.error("会话验证失败:", error);
      return {
        success: false,
        message: "会话验证失败",
        code: "SESSION_VALIDATE_ERROR"
      };
    }
  }

  /**
   * 用户登出
   * @param sessionId 会话ID
   * @returns 登出结果
   */
  public async logout(sessionId: string) {
    const { models } = this.app as any;

    try {
      // 标记会话为失效
      const [affectedRows] = await models.UserSession.update(
        {
          is_active: 0
        },
        {
          where: { session_id: sessionId }
        }
      );

      return {
        success: true,
        message: "登出成功",
        data: { affectedRows }
      };
    } catch (error) {
      this.logger.error("用户登出失败:", error);
      return {
        success: false,
        message: "登出失败",
        code: "LOGOUT_ERROR"
      };
    }
  }

  /**
   * 获取用户列表（分页）
   * @param page 页码
   * @param pageSize 每页数量
   * @returns 用户列表
   */
  public async getUserList(page = 1, pageSize = 10) {
    const { models } = this.app as any;

    try {
      const offset = (page - 1) * pageSize;

      const { count, rows } = await models.User.findAndCountAll({
        attributes: ["id", "username", "status", "login_count", "last_login_at", "created_at"],
        order: [["created_at", "DESC"]],
        limit: pageSize,
        offset
      });

      return {
        success: true,
        data: {
          users: rows,
          pagination: {
            total: count,
            page,
            pageSize,
            totalPages: Math.ceil(count / pageSize)
          }
        }
      };
    } catch (error) {
      this.logger.error("获取用户列表失败:", error);
      return {
        success: false,
        message: "获取用户列表失败",
        code: "GET_USER_LIST_ERROR"
      };
    }
  }

  /**
   * 清理过期会话
   */
  public async cleanExpiredSessions() {
    const { models } = this.app as any;

    try {
      const [affectedRows] = await models.UserSession.update(
        { is_active: 0 },
        {
          where: {
            expires_at: {
              [Op.lt]: new Date()
            },
            is_active: 1
          }
        }
      );

      this.logger.info(`清理了 ${affectedRows} 个过期会话`);

      return {
        success: true,
        data: { cleanedSessions: affectedRows }
      };
    } catch (error) {
      this.logger.error("清理过期会话失败:", error);
      return {
        success: false,
        message: "清理过期会话失败",
        code: "CLEAN_SESSIONS_ERROR"
      };
    }
  }

  /**
   * 生成密码盐值
   * @returns 随机盐值
   */
  private generateSalt(): string {
    return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
  }

  /**
   * 密码哈希加密
   * @param password 明文密码
   * @param salt 盐值
   * @returns 哈希后的密码
   */
  private async hashPassword(password: string, salt: string): Promise<string> {
    // 使用bcrypt进行密码哈希，成本因子为10
    return await bcrypt.hash(password + salt, 10);
  }

  /**
   * 验证密码
   * @param password 明文密码
   * @param hash 存储的哈希值
   * @param salt 盐值
   * @returns 验证结果
   */
  private async verifyPassword(password: string, hash: string, salt: string): Promise<boolean> {
    return await bcrypt.compare(password + salt, hash);
  }
}
